<?php
/**
 * Name: 数据处理类
 * User: Small_K
 * Date: 2018/1/11
 * Time: 10:28
 */

namespace App\Services\Tool;

/**
 * Class Data
 * @package App\Service\Tool
 *
 * 数据处理类
 * 注意:定义值时直接定义 public static function
 * <code>
 *  public static function del(array $array, $a)
 * </code>
 * 此类已经在 config/app.php 中aliases数组中注册
 *
 * 代码调用方法
 * <code>
 *  Data::del($array,$a)
 * </code>
 */

class Data
{

    /**
     *
     * 返回多层栏目
     *
     * @param array $data 操作的数组
     * @param int $pid 以及PID的值
     * @param string $html 栏目名称前缀
     * @param string $fieldPri 唯一键名，如果是表这是主键
     * @param string $fieldPid 父ID键名
     * @param int $level 不需要传参 (执行时调用)
     *
     * @return array
     */
    public static function channelLevel($data, $pid = 0, $html = "&nbsp;", $fieldPri = 'cid', $fieldPid = 'pid', $level = 1)
    {
        if (empty($data)) {
            return [];
        }
        $arr = [];
        foreach ($data as $v) {
            if ($v[$fieldPid] == $pid) {
                $arr[$v[$fieldPri]] = $v;
                $arr[$v[$fieldPri]]['_level'] = $level;
                $arr[$v[$fieldPri]]['_html'] = str_repeat($html, $level - 1);
                $arr[$v[$fieldPri]]["_data"] = self::channelLevel($data, $v[$fieldPri], $html, $fieldPri, $fieldPri, $level + 1);
            }
        }
        return $arr;
    }

    /**
     *
     * 获得栏目列表
     *
     * @param array $array 栏目数据
     * @param int $pid 操作的栏目
     * @param string $html 栏目名前字符
     * @param string $fieldPri 唯一键名，如果是表这是主键
     * @param string $fieldPid 父ID键名
     * @param int $level 等级
     *
     * @return array
     */
    public static function channelList($array, $pid = 0, $html = "&nbsp;", $fieldPri = 'cid', $fieldPid = 'pid', $level = 1)
    {
        $pid = is_array($pid) ? $pid : [$pid];
        $data = [];
        foreach ($pid as $id) {
            $res = self::_channelList($array, $id, $html, $fieldPri, $fieldPid, $level);
            foreach ($res as $k => $v) {
                $data[$k] = $v;
            }
        }
        if (empty($data)) {
            return $data;
        }
        foreach ($data as $n => $m) {
            if ($m['_level'] == 1) {
                continue;
            }
            $data[$n]['_first'] = false;
            $data[$n]['_end'] = false;
            if (!isset($data[$n - 1]) || $data[$n - 1]['_level'] != $m['_level']) {
                $data[$n]['_first'] = true;
            }
            if (isset($data[$n + 1]) && $data[$n]['_level'] > $data[$n + 1]['_level']) {
                $data[$n]['_end'] = true;
            }
        }
        //更新key为栏目主键
        $category = [];
        foreach ($data as $d) {
            $category[$d[$fieldPri]] = $d;
        }
        return $category;
    }

    /**
     *
     * 只用channelList方法使用
     *
     * @param $data
     * @param int $pid
     * @param string $html
     * @param string $fieldPri
     * @param string $fieldPid
     * @param int $level
     * @return array
     */
    private static function _channelList($data, $pid = 0, $html = "&nbsp;", $fieldPri = 'cid', $fieldPid = 'pid', $level = 1)
    {
        if (empty($data)) {
            return [];
        }
        $arr = [];
        foreach ($data as $v) {
            $id = $v[$fieldPri];
            if ($v[$fieldPid] == $pid) {
                $v['_level'] = $level;
                $v['_html'] = str_repeat($html, $level - 1);
                array_push($arr, $v);
                $tmp = self::_channelList($data, $id, $html, $fieldPri, $fieldPid, $level + 1);
                $arr = array_merge($arr, $tmp);
            }
        }
        return $arr;
    }

    /**
     *
     * 获得树状数据
     *
     * @param array $data 数据
     * @param string $title 字段名
     * @param string $fieldPri 主键Id
     * @param string $fieldPid 父id
     *
     * @return array
     */
    public static function tree($data, $title, $fieldPri = 'cid', $fieldPid = 'pid')
    {
        if (!is_array($data) || empty($data)) {
            return [];
        }
        $arr = self::channelList($data, 0, '', $fieldPri, $fieldPid);
        foreach ($arr as $k => $v) {
            $str = '';
            if ($v['_level'] > 2) {
                for ($i = 1; $i < $v['_level'] - 1; $i++) {
                    $str .= "|&nbsp;&nbsp;&nbsp;&nbsp;";
                }
            }
            if ($v['_level'] != 1) {
                $t = $title ? $v[$title] : '';
                if (isset($arr[$k + 1]) && $arr[$k + 1]['_level'] >= $arr[$k]['_level']) {
                    $arr[$k]['_' . $title] = $str . "├─" . $v['_html'] . $t;
                } else {
                    $arr[$k]['_' . $title] = $str . "└─" . $v['_html'] . $t;
                }
            } else {
                $arr[$k]['_' . $title] = $v[$title];
            }
        }
        //设置主键为$fieldPri
        $data = [];
        foreach ($arr as $d) {
            $data[] = $d;
        }
        return $data;
    }

    /**
     *
     * 获得所有父级栏目
     *
     * @param array $data 栏目数据
     * @param int $sid 子栏目
     * @param string $fieldPri 唯一键名,如果是表则是主键
     * @param string $fieldPid 父ID键名
     *
     * @return array
     */
    public static function parentChannel($data, $sid, $fieldPri = 'cid', $fieldPid = 'pid')
    {
        if (empty($data)) {
            return $data;
        } else {
            $arr = [];
            foreach ($data as $v) {
                if ($v[$fieldPri] == $sid) {
                    $arr[] = $v;
                    $_n = self::parentChannel($data, $v[$fieldPri], $v[$fieldPid]);
                    if (!empty($_n)) {
                        $arr = array_merge($arr, $_n);
                    }
                }
            }
            return $arr;
        }
    }

    /**
     *
     * 判断是否有子级
     *
     * @param array $data 栏目数据
     * @param int $sid 子栏目id
     * @param int $pid 父栏目id
     * @param string $fieldPri 唯一键名,如果是表则是主键
     * @param string $fieldPid 父id字段
     *
     * @return bool
     */

    public static function isChild($data, $sid, $pid, $fieldPri = 'cid', $fieldPid = 'pid')
    {
        $_data = self::channelList($data, $pid, '', $fieldPri, $fieldPid);
        foreach ($_data as $c) {
            if ($c[$fieldPri] == $sid) {
                return true;
            }
        }
        return false;
    }

    /**
     *
     * 递归实现笛卡尔乘积
     *
     * @param array $arr 操作的数组
     * @param array $tmp
     *
     * @return array
     */

    public static function desArte($arr, $tmp = [])
    {
        $n_arr = [];
        foreach (array_shift($arr) as $v) {
            $tmp[] = $v;
            if ($arr) {
                self::desArte($arr, $tmp);
            } else {
                $n_arr[] = $tmp;
            }
            array_pop($tmp);
        }
        return $n_arr;
    }

    /**
     *
     * 从数组中移除给定的值
     *
     * @param array $data 原数组数据
     * @param array $values 要移除的值
     *
     * @return array
     */
    public static function del(array $data, array $values)
    {
        $news = [];
        foreach ($data as $k => $v) {
            if (!in_array($v, $values)) {
                $news[$k] = $v;
            }
        }
        return $news;
    }

    /**
     *
     * 根据键名获取数据
     * 如果键名不存在时返回默认值
     *
     * @param array $data 数据
     * @param string $key 名称
     * @param null $value 默认值
     *
     * @return array|mixed|null
     */
    public static function get(array $data, $key, $value = null)
    {
        $exp = explode('.', $key);
        foreach ((array)$exp as $item) {
            if (isset($data[$item])) {
                $data = $data[$item];
            } else {
                return $value;
            }
        }
        return $data;
    }

    /**
     *
     * 排字段获取数据
     *
     * @param array $data 数据
     * @param array $extName 排除的字段
     * @return array
     */
    public static function getExtName(array $data, array $extName)
    {
        $extData = [];
        foreach ((array)$data as $k => $v) {
            if (!in_array($k, $extName)) {
                $extData[$k] = $v;
            }
        }
        return $extData;
    }

    /**
     *
     * 设置数组元素值支持点语法
     *
     * @param array $data 数据
     * @param string $key
     * @param string $value
     * @return array|mixed
     */
    public static function set(array $data, $key, $value)
    {
        $tmp =& $data;
        foreach (explode('.', $key) as $v) {
            if (!isset($tmp[$v])) {
                $tmp[$v] = [];
            }
            $tmp = &$tmp[$v];
        }
        $tmp = $value;
        return $tmp;
    }

    /**
     *
     * 将数组键名变成大写或小写
     *
     * @param array $arr 数组
     * @param int $type 类型 1大写 0小写
     *
     * @return array
     */
    public static function keyCase($arr, $type = 0)
    {
        $func = $type ? 'strtoupper' : 'strtolower';
        $data = []; //格式化后的数组
        foreach ($arr as $k => $v) {
            $k = $func($k);
            $data[$k] = is_array($v) ? self::keyCase($v, $type) : $v;
        }
        return $data;
    }

    /**
     *
     * 不区分大小写检查数据键名是否纯存在
     *
     * @param $key
     * @param $arr
     * @return bool
     */
    public static function keyExists($key, $arr)
    {
        return array_key_exists(strtolower($key), $arr);
    }

    /**
     *
     * 将数组中的值全部转换成大写或者小写
     *
     * @param array $arr 数组
     * @param int $type 类型 1大写 0小写
     * @return array
     */
    public static function valueCase($arr, $type = 0)
    {
        $func = $type ? 'strtoupper' : 'strtolower';
        $data = []; //格式化后的数组
        foreach ($arr as $k => $v) {
            $data[$k] = is_array($v) ? self::valueCase($v, $type) : $func($v);
        }
        return $data;
    }

    /**
     *
     * 数组进行整数
     *
     * @param array $arr
     * @param array $mp
     */
    public static function intToString($arr, array $mp = ['status' => ['0' => '禁止', '1' => '启用']])
    {
        foreach ($mp as $name => $m) {
            if (isset($arr[$name]) && array_key_exists($arr[$name], $m)) {
                $arr['_' . $name] = $m[$arr[$name]];
            }
        }
    }

    /**
     *
     * 数组中的字符串数字转为INT类型
     *
     * @param array $data 数据
     * @return mixed
     */
    public static function stringToInt($data)
    {
        $tmp = $data;
        foreach ((array)$tmp as $k => $v) {
            $tmp[$k] = is_array($v) ? self::stringToInt($v) : (is_numeric($v) ? intval($v) : $v);
        }
        return $tmp;
    }

    /**
     * @param array $data 原数组数据
     * @param array $keys 参数的下标
     * @param int $type 1存在再$keys时过滤 0不在的时候过滤
     * @return array
     */

    public static function filterKeys(array $data, $keys, $type = 1)
    {
        $tmp = $data;
        foreach ($data as $k => $v) {
            if ($type == 1) {
                //在的时候过滤
                if (!in_array($k, $keys)) {
                    unset($tmp[$k]);
                }
            } else {
                //不在的时候过滤
                if (!in_array($k, $keys)) {
                    unset($tmp[$k]);
                }
            }
        }
        return $tmp;
    }


}